package com.fumin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fumin.mapper.CapitalMapper;
import com.fumin.mapper.InvestmentRecordMapper;
import com.fumin.mapper.RefundRecordMapper;
import com.fumin.pojo.Capital;
import com.fumin.pojo.InvestmentRecord;
import com.fumin.pojo.RefundRecord;
import com.fumin.service.CapitalService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Numeric;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Lingo on 2018/3/8.
 */
@Service
public class CapitalServiceImpl implements CapitalService {

    // 充值
    private static String CHARGE="充值";
    // 退款
    private static String REFUND = "退款";
    // 投资
    private static  String INVESTMENT = "投资";
    // 提现
    private static  String WITHDRAW = "提现";


    private static Logger logger = Logger.getLogger(CapitalServiceImpl.class);



    @Resource
    CapitalMapper capitalMapper;
    @Resource
    InvestmentRecordMapper investmentRecordMapper;
    @Resource
    RefundRecordMapper refundRecordMapper;

    @Override
    public int deleteByPrimaryKey(Long pk) {
        return capitalMapper.deleteByPrimaryKey(pk);
    }

    @Override
    public int insert(Capital record) {
        return capitalMapper.insert(record);
    }

    @Override
    public int insertSelective(Capital record) {
        return capitalMapper.insertSelective(record);
    }

    @Override
    public Capital selectByPrimaryKey(Long pk) {
        return capitalMapper.selectByPrimaryKey(pk);
    }

    @Override
    public int updateByPrimaryKeySelective(Capital record) {
        return capitalMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(Capital record) {
        return capitalMapper.updateByPrimaryKey(record);
    }

    @Override
    public List<Capital> selectByUserPk(Long UserPk) {
        return capitalMapper.selectByUserPk(UserPk);
    }

    @Override
    public List<Capital> selectAllColumnsByUserPk(Long UserPk) {
        return capitalMapper.selectAllColumnsByUserPk(UserPk);
    }

    @Override
    public Float getBlanceByAddr(String addr) {
        String url = "https://api.etherscan.io/api?module=account&action=balance&" +
                "address=%s" +
                "&tag=latest&" +
                "apikey=%s";
        url = String.format(url,addr,"H6T8WITXFCYG189UEFV2FTNAGWZQIFWHQW");

        HttpResponse<String> response  = null;
        try {
            response = Unirest.get(url)
                    .header("cache-control", "no-cache")
                    .header("postman-token", "01e8236c-7f07-2b64-833e-0a5403afd5d9")
                    .asString();
        } catch (UnirestException e) {
            logger.error(e.getMessage());
            return null;
        }
        String body = response.getBody();
        JSONObject resuelt = JSON.parseObject(body);
        logger.debug("钱包余额：\n"+resuelt);
        String ethResutlt = resuelt.getString("result");
        Float longValue = Float.valueOf(ethResutlt);
        return longValue/1000000000000000000F;
    }

    /**
     *  查看交易记录
     * @param addr
     * @return
     */
    @Override
    public JSONArray getTransactionRecords(String addr,Long user_pk) {

        JSONArray ethResutlt = getAllTransactionRecords(addr);
        if (ethResutlt==null || ethResutlt.size()<1){
            return new JSONArray();
        }
        JSONArray inputRecord = getRecordByType(ethResutlt,addr,true);
        markInPutRecord(inputRecord,user_pk);
        JSONArray outputRecord = getRecordByType(ethResutlt,addr,false);
        markOutPutRecord(outputRecord,user_pk);

        return souredByTimestamp(mergeData(inputRecord,outputRecord));
    }

    /**
     *   获取充值交易记录
     * @param addr
     * @param user_pk
     * @return
     */
    @Override
    public JSONArray getTransactionChargeRecords(String addr, Long user_pk) {
        JSONArray ethResutlt = getAllTransactionRecords(addr);
        JSONArray inputRecord = getRecordByType(ethResutlt,addr,true);
        markInPutRecord(inputRecord,user_pk);
        return souredByTimestamp(selectByLaber(inputRecord,CHARGE));
    }

    /**
     *   获取退款交易记录
     * @param addr
     * @param user_pk
     * @return
     */
    @Override
    public JSONArray getTransactionRefundRecords(String addr, Long user_pk) {
        JSONArray ethResutlt = getAllTransactionRecords(addr);
        JSONArray inputRecord = getRecordByType(ethResutlt,addr,true);
        markInPutRecord(inputRecord,user_pk);
        return  souredByTimestamp(selectByLaber(inputRecord,REFUND));
    }

    /**
     *   获取投资交易记录
     * @param addr
     * @param user_pk
     * @return
     */
    @Override
    public JSONArray getTransactionInvestmentRecords(String addr, Long user_pk) {
        JSONArray ethResutlt = getAllTransactionRecords(addr);
        JSONArray outputRecord = getRecordByType(ethResutlt,addr,false);
        markOutPutRecord(outputRecord,user_pk);
        return souredByTimestamp(selectByLaber(outputRecord,INVESTMENT));
    }
    /**
     *   获取提现交易记录
     * @param addr
     * @param user_pk
     * @return
     */
    @Override
    public JSONArray getTransactionWithdrawRecords(String addr, Long user_pk) {
        JSONArray ethResutlt = getAllTransactionRecords(addr);
        JSONArray outputRecord = getRecordByType(ethResutlt,addr,false);
        markOutPutRecord(outputRecord,user_pk);
        return souredByTimestamp(selectByLaber(outputRecord,WITHDRAW));
    }

    @Override
    public List<InvestmentRecord> getInvestmentRecords(String addr, Long user_pk) {
        return investmentRecordMapper.selectByUserPk(user_pk);
    }

    /**
     *  查询地址的ETH交易记录（外部API）
     * @param addr
     * @return
     */
    public JSONArray getAllTransactionRecords(String addr){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String url = "http://api.etherscan.io/api?module=account&action=txlist&" +
                "address=%s" +
                "&startblock=0&endblock=99999999&sort=desc&" +
                "apikey=%s";
        url = String.format(url,addr,"H6T8WITXFCYG189UEFV2FTNAGWZQIFWHQW");

        HttpResponse<String> response  = null;
        try {
            response = Unirest.get(url)
                    .header("cache-control", "no-cache")
                    .header("postman-token", "01e8236c-7f07-2b64-833e-0a5403afd5d9")
                    .asString();
        } catch (UnirestException e) {
            logger.error(e.getMessage());
            return null;
        }
        String body = response.getBody();
        JSONObject resuelt = JSON.parseObject(body);
        JSONArray ethResutlt = resuelt.getJSONArray("result");
        for (int i = 0; i <ethResutlt.size() ; i++) {
            JSONObject temp = ethResutlt.getJSONObject(i);
            Date date = new Date(Long.valueOf(temp.getString("timeStamp")+"000"));
            temp.put("sort",Long.valueOf(temp.getString("timeStamp")));
            temp.put("timeStamp",simpleDateFormat.format(date));
            Float longValue =Float.valueOf(temp.getString("value"));
            temp.put("value",longValue/1000000000000000000F);
            Long longGas =Long.valueOf(temp.getString("gasUsed"));
            Long longGasPrise =Long.valueOf(temp.getString("gasPrice"));
            Long tx = longGas*longGasPrise;
            Float longTx =Float.valueOf(tx.toString());
            temp.put("gasUsed",longTx/1000000000000000000F);
        }
        return ethResutlt;
    }


    /**
     *  筛选交易记录类型（按照进帐出账筛选）
     * @param ethResutlt
     * @param in true 进帐 false 出账
     * @return
     */
    private JSONArray getRecordByType(JSONArray ethResutlt,String addr,boolean in){
        addr=addr.toUpperCase();
        // 无交易记录返回空值
        if(ethResutlt==null ||ethResutlt.size()==0){
            return new JSONArray();
        }
        JSONArray result =  new JSONArray();
        if (in){
            //迭代 eth接口数据
            for (int i = 0; i <ethResutlt.size() ; i++) {
                // 如果接收地址于用户地址相同，则该数据为进帐数据
                String inputAddr = ethResutlt.getJSONObject(i).getString("to").toUpperCase();
                if (addr.equals(inputAddr)){
                    result.add(ethResutlt.getJSONObject(i));
                }
            }
        }else {
            //迭代 eth接口数据
            for (int i = 0; i <ethResutlt.size() ; i++) {
                // 如果发送地址于用户地址相同，则该数据为出账数据
                String outputAddr = ethResutlt.getJSONObject(i).getString("from").toUpperCase();
                if (addr.equals(outputAddr)){
                    result.add(ethResutlt.getJSONObject(i));
                }
            }
        }
        return result;
    }


    /**
     *  对出帐数据进行分类,并添加数据标签 transaction_type
     *
     * @param outputRecord ETH交易记录
     * @param user_pk 用户主键
     */
    private void markOutPutRecord(JSONArray outputRecord,Long user_pk){
        // 查询用户的投资记录
        List<InvestmentRecord> investmentRecords = investmentRecordMapper.selectByUserPk(user_pk);
        // 过滤筛选出帐数据
        for (int i = 0; i <outputRecord.size() ; i++) {
            String transactionHash = outputRecord.getJSONObject(i).getString("hash").toUpperCase();
            // 根据交易hash 迭代遍历

            // 逻辑开关，用于判断是否为投资记录
            boolean flag=true;
            for (InvestmentRecord record :investmentRecords) {
                // 该交易数据为投资记录
                if (record.getTransaction_hash().toUpperCase().equals(transactionHash)){
                    // 添加数据标签 --  "transaction_type":"investment"
                    outputRecord.getJSONObject(i).put("transaction_type",INVESTMENT);
                    flag=false;
                }
            }
            // 该交易不是投资记录 - - - -认为该交易为提现交易
            // 添加数据标签 --  "transaction_type":"withdraw"
            if (flag){
                outputRecord.getJSONObject(i).put("transaction_type",WITHDRAW);
            }

        }
    }

    /**
     *  对入帐数据进行分类,并添加数据标签 transaction_type
     *
     * @param InputRecords ETH交易记录
     * @param user_pk 用户主键
     */
    private void markInPutRecord(JSONArray InputRecords,Long user_pk){
        // 查询用户的投资记录
        List<RefundRecord> refundRecords = refundRecordMapper.selectByUserPk(user_pk);
        // 过滤筛选出帐数据
        for (int i = 0; i <InputRecords.size() ; i++) {
            String transactionHash = InputRecords.getJSONObject(i).getString("hash").toUpperCase();
            // 根据交易hash 迭代遍历

            // 逻辑开关，用于判断是否为投资失败退款记录
            boolean flag=true;
            for (RefundRecord record :refundRecords) {
                // 该交易数据为投资失败退款记录
                if (record.getTransaction_hash().toUpperCase().equals(transactionHash)){
                    // 添加数据标签 --  "transaction_type":"refund"
                    InputRecords.getJSONObject(i).put("transaction_type",REFUND);
                    // 该交易不是投资记录 - - - -认为该交易为充值
                    flag=false;
                }
            }
             if (flag){
                // 添加数据标签 --  "transaction_type":"charge"
                InputRecords.getJSONObject(i).put("transaction_type",CHARGE);
            }
        }
    }

    /**
     *  合并所有(含标签的)交易数据
     * @param InputRecords
     * @param outputRecord
     * @return
     */
    private JSONArray mergeData(JSONArray InputRecords,JSONArray outputRecord){
        for (int i = 0; i <outputRecord.size() ; i++) {
            InputRecords.add(outputRecord.getJSONObject(i));
        }
        return InputRecords;
    }


    /**
     *  根据交易类型名称，筛选交易记录
     * @param data
     * @param laber
     * @return
     */
    private JSONArray selectByLaber(JSONArray data,String laber){
        JSONArray result =  new JSONArray();
        for (int i = 0; i < data.size(); i++) {
            if (data.getJSONObject(i).getString("transaction_type").equals(laber)){
                result.add(data.getJSONObject(i));
            }
        }
        return result;
    }

    /**
     *  按时间排序
     * @param input
     * @return
     */
    @Override
    public JSONArray souredByTimestamp(JSONArray input) {
        TreeMap<Long,JSONObject> treeMap = new TreeMap<>();
        for (int i = 0; i <input.size() ; i++) {
            long sort = input.getJSONObject(i).getLong("sort");
            treeMap.put(sort,input.getJSONObject(i));
        }
        JSONArray result = new JSONArray();
        for (Long key:treeMap.keySet()) {
            result.add(treeMap.get(key));
        }
        Collections.reverse(result);
        return result;
    }
}
